package com.dingup.mock.controller.exam;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dingup.api.Util.JwtTokenUtil;
import com.dingup.api.Util.RedisUtils;
import com.dingup.api.base.HttpResContent;
import com.dingup.mock.bean.exam.*;
import com.dingup.mock.bean.listening.*;
import com.dingup.mock.bean.reading.*;
import com.dingup.mock.bean.speaking.ExamSpeakingInfo;
import com.dingup.mock.bean.speaking.SpeakingAnswerInfo;
import com.dingup.mock.bean.speaking.TsSpeakingQuestion;
import com.dingup.mock.bean.writing.ExamWritingInfo;
import com.dingup.mock.bean.writing.TsWritingQuestion;
import com.dingup.mock.bean.writing.WritingAnswerInfo;
import com.dingup.mock.dao.exam.TsExamRecordsMapper;
import com.dingup.mock.dao.exam.TsMockMarkRecordsMapper;
import com.dingup.mock.dao.exam.TsMockReportsMapper;
import com.dingup.mock.dao.listening.TsListeningArticlesMapper;
import com.dingup.mock.dao.listening.TsListeningQuestionsMapper;
import com.dingup.mock.dao.reading.TsReadingArticleDAO;
import com.dingup.mock.dao.reading.TsReadingQuestionDAO;
import com.dingup.mock.dao.speaking.TsSpeakingQuestionsMapper;
import com.dingup.mock.dao.writing.TsWritingQuestionsMapper;
import com.dingup.mock.enums.*;
import com.dingup.mock.feign.client.UserFeignClient;
import com.dingup.mock.module.SExamCookieManager;
import com.dingup.mock.module.SExaminationQueueCache;
import com.dingup.mock.service.HomeworkRecordService;
import com.dingup.mock.util.ConstUtil;
import com.dingup.mock.util.MockUtil;
import com.dingup.util.GJsonUtil;
import com.google.gson.Gson;
import com.suyeer.basic.util.BHttpResUtil;
import com.suyeer.basic.util.BLogUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static com.dingup.api.base.BaseUtil.*;
import static com.dingup.mock.util.ConstUtil.*;

/**
 * Created by yanggavin on 16/5/7.
 */
@Controller
@RequestMapping("/exam")
public class ExamController {
    @Autowired
    private TsReadingArticleDAO tsReadingArticleDAO;
    @Autowired
    private TsReadingQuestionDAO tsReadingQuestionDAO;
    @Autowired
    private TsListeningArticlesMapper tsListeningArticlesMapper;
    @Autowired
    private TsListeningQuestionsMapper tsListeningQuestionsMapper;
    @Autowired
    private TsSpeakingQuestionsMapper tsSpeakingQuestionsMapper;
    @Autowired
    private TsWritingQuestionsMapper tsWritingQuestionsMapper;
    @Autowired
    private TsExamRecordsMapper tsExamRecordsMapper;
    @Autowired
    private TsMockMarkRecordsMapper tsMockMarkRecordsMapper;
    @Autowired
    private TsMockReportsMapper tsMockReportsMapper;
    @Autowired
    private HomeworkRecordService homeworkRecordService;
    @Autowired
    private UserFeignClient userFeignClient;


    //阅读计算分数规则
    private Integer[] readingGrad = {0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29, 30};
    //听力计算分数规则
    private Integer[] listenGrad = {0, 0, 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 11, 13, 14, 15, 15, 16, 17, 19, 21, 22, 23, 24, 25, 26, 27, 29, 30};
    private Integer fullScore = 30;//阅读,听力各自的总分数
    private String[] listeningLacks = {"TPO1", "20150412_real_test", "20150711_real_test", "20150919_real_test"};//听力缺少一题,默认加一分

    @RequestMapping(value = "/start.do", method = RequestMethod.POST)
    public void startExam(@RequestParam(ConstUtil.REQUEST_PARAMETER_SUBJECT_NAME) String subjectName,
                          @RequestParam(ConstUtil.REQUEST_PARAMETER_EXAM_TYPE) String examType,
                          @RequestParam(ConstUtil.REQUEST_PARAMETER_EXAM_CONTENT_TYPE) String examContentType,
                          @RequestParam(value = ConstUtil.REQUEST_PARAMETER_HOMEWORK_RECORD_ID, required = false) Integer hrId,
                          @RequestParam(value = ConstUtil.REQUEST_PARAMETER_HOMEWORK_QUESTION_NUM, required = false) Integer hqNum,
                          HttpServletRequest request,
                          HttpServletResponse response) {
        HttpResContent<String> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("开始考试");
        try {
            String userId = RedisUtils.getInstance().getUserId(request);
            String userAccount = JwtTokenUtil.getUserAccountFromRequset(request);
            // check.
            checkParam(ConstUtil.REQUEST_PARAMETER_SUBJECT_NAME, subjectName);
            // 考试类型默认为PRACTICE
            examType = (StringUtils.isBlank(examType) ? ExamTypeEnum.PRACTICE.getCode() : examType.toUpperCase());
            // 考试默认类型为DEFAULT
            examContentType = (StringUtils.isBlank(examContentType) ? ExamContentTypeEnum.DEFAULT.getCode() : examContentType.toUpperCase());
            checkParam(ConstUtil.REQUEST_PARAMETER_EXAM_TYPE, examType);
            checkParam(ConstUtil.REQUEST_PARAMETER_EXAM_CONTENT_TYPE, examContentType);
            // set some sample data.
            ExaminationInfo ei = new ExaminationInfo();
            ei.setExamType(ExamTypeEnum.valueOf(examType.toUpperCase()));
            ei.setExamContentType(ExamContentTypeEnum.valueOf(examContentType.toUpperCase()));
            ei.setSubjectName(subjectName);
            ei.setUserId(userId);
            ei.setUserAccount(userAccount);

            // 根据考试内容类型来填充当前考试的内容
            String numData = request.getParameter(ConstUtil.REQUEST_PARAMETER_EXAM_QUESTION_NUM_DATA);
            if (ei.getExamContentType() == ExamContentTypeEnum.ALL) {
                ei.setExamReadingInfo(getBlankExamReadingInfo(subjectName, numData));
                ei.setExamListeningInfo(getBlankExamListeningInfo(subjectName, numData));
                ei.setExamSpeakingInfo(getBlankExamSpeakingInfo(subjectName, numData));
                ei.setExamWritingInfo(getBlankExamWritingInfo(subjectName, numData));
            } else if (ei.getExamContentType() == ExamContentTypeEnum.READING) {
                ei.setExamReadingInfo(getBlankExamReadingInfo(subjectName, numData));
            } else if (ei.getExamContentType() == ExamContentTypeEnum.LISTENING) {
                ei.setExamListeningInfo(getBlankExamListeningInfo(subjectName, numData));
            } else if (ei.getExamContentType() == ExamContentTypeEnum.SPEAKING) {
                ei.setExamSpeakingInfo(getBlankExamSpeakingInfo(subjectName, numData));
            } else if (ei.getExamContentType() == ExamContentTypeEnum.WRITING) {
                ei.setExamWritingInfo(getBlankExamWritingInfo(subjectName, numData));
            }
            if (hrId != null && hqNum != null) {
                Integer homeworkId = homeworkRecordService.getHomeworkIdByHomeworkRecordId(hrId);
                ei.setHomeworkId(homeworkId);
                ei.setHomeworkRecordId(hrId);
                ei.setHomeworkQuestionNum(hqNum);
            }
            // add to global examination queue.
            SExaminationQueueCache.getInstance().addItem(ei);
            // 清除过期的本地考试实例
            SExaminationQueueCache.getInstance().clearExpiredExaminationInfos(tsExamRecordsMapper);
            // 种入特殊的考试过程免登陆的token凭证
            SExamCookieManager.getInstance().setExamTokenCookie(response, userId, ei.getId());
            // save and response.
            saveSuccessMsgAndData(hrc, ei.getId());
        } catch (Exception e) {
            e.printStackTrace();
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    @RequestMapping(value = "/check_exam_id.do", method = RequestMethod.POST)
    public void checkExamId(@RequestParam(REQUEST_PARAMETER_EXAMINATION_ID) String examinationId,
                            HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<Boolean> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("检查考试ID是否存在缓存");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_EXAMINATION_ID, examinationId);
            // do.
            Boolean ret = SExaminationQueueCache.getInstance().containsExamId(examinationId);
            // response.
            saveSuccessMsgAndData(hrc, ret);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    @RequestMapping(value = "/finish.do", method = RequestMethod.POST)
    public void finishExam(@RequestParam(REQUEST_PARAMETER_EXAMINATION_ID) String examinationId,
                           HttpServletRequest request,
                           HttpServletResponse response) {
        HttpResContent<TsExamRecord> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("完成考试");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_EXAMINATION_ID, examinationId);
            ExaminationInfo ei = SExaminationQueueCache.getInstance().getExaminationInfo(examinationId);
            if (ei == null) {
                throw new Exception("找不到对应考试id的考试记录");
            }
            // set and save.
            ExamSummaryInfo examSummaryInfo = getExamSummaryInfo(ei);
            String examSummaryInfoStr = (new Gson()).toJson(getExamSummaryInfo(ei));
            TsExamRecord ter = new TsExamRecord();
            ter.setExamId(examinationId);
            ter.setSubjectName(ei.getSubjectName());
            ter.setUserId(ei.getUserId());
            ter.setExamType(ei.getExamType());
            ter.setExamContentType(ei.getExamContentType());
            ter.setBeginTime(ei.getBeginTime());
            ter.setEndTime(new Date());
            ter.setExamSummaryInfo(examSummaryInfoStr);
            ter.setRecordType(ExamRecordTypeEnum.NORMAL);
            // 判断是否含有homework_record_id和homework_question_num参数,如果有,则进行保存
            Boolean ifHomework = false;
            Integer hrId = ei.getHomeworkRecordId();
            Integer qNum = ei.getHomeworkQuestionNum();
            if (!hrId.equals(0) && !qNum.equals(0)) {
                ifHomework = true;
                ter.setHomeworkRecordId(hrId);
                ter.setHomeworkQuestionNum(qNum);
                // 为了避免重复做作业中的某道题,如果匹配homework_record_id和homework_question_num两个参数,
                // 则删除原有记录,插入新纪录进行覆盖
                searchExistHomeworkExamRecordAndDelete(hrId, qNum);
            }
            if (!tsExamRecordsMapper.exist(examinationId)) {
                if (!tsExamRecordsMapper.add(ter)) {
                    throw new Exception("保存考试统计信息失败");
                }
                if (ifHomework) {
                    // 保存作业进度
                    AnswerResultInfo answerResultInfo = new AnswerResultInfo();
                    if (ter.getExamContentType() == ExamContentTypeEnum.READING) {
                        answerResultInfo = examSummaryInfo.getReadingAnswerResult();
                    }
                    if (ter.getExamContentType() == ExamContentTypeEnum.LISTENING) {
                        answerResultInfo = examSummaryInfo.getListeningAnswerResult();
                    }
                    Integer correct = answerResultInfo.getCorrect();
                    Integer total = answerResultInfo.getTotal();
                    homeworkRecordService.saveHomeworkProgress(hrId, qNum, ter.getId(), examinationId, correct, total);
                }
                BLogUtil.info("保存考试统计信息成功.");
                // 模考
                if (ExamTypeEnum.MOCK == ter.getExamType()) {
                    BLogUtil.info("整套模考报告及评分记录生成ing.");
                    String currentUserName = userFeignClient.getUserNameByUserId(ter.getUserId());
                    if ((ter.getExamContentType() == ExamContentTypeEnum.ALL ||
                            ter.getExamContentType() == ExamContentTypeEnum.READING ||
                            ter.getExamContentType() == ExamContentTypeEnum.LISTENING)
                            && !createMockReport(ter, currentUserName)) {
                        throw new Exception("生成报告失败");
                    }
                    // 增加评分记录
                    if (!saveMockMarkRecord(ter)) {
                        throw new Exception("保存考试统计信息失败");
                    }
                }
                // clear cache.
                SExaminationQueueCache.getInstance().removeExaminationInfo(examinationId);
                SExamCookieManager.getInstance().delExamTokenCookie(response);
                BLogUtil.info("模考缓存记录清除成功:" + ter.getExamId());
            }
            //保存老师批改记录
            homeworkRecordService.updateTeacherCorrect(hrId, ter.getExamId(), ter.getId(), new Date());
            // response.
            saveSuccessMsgAndData(hrc, ter);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    /**
     * 清除考试缓存数据
     *
     * @param examinationId
     * @param request
     * @param response
     */
    @RequestMapping(value = "/remove_exam_cache.do", method = RequestMethod.POST)
    public void removeUselessExamDataCache(@RequestParam(REQUEST_PARAMETER_EXAMINATION_ID) String examinationId,
                                           HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<Boolean> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("清除考试缓存数据");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_EXAMINATION_ID, examinationId);
            // do.
            SExaminationQueueCache.getInstance().removeExaminationInfo(examinationId);
            SExamCookieManager.getInstance().delExamTokenCookie(response);
            // response.
            saveSuccessMsgAndData(hrc, true);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    /**
     * 查询并判断是否存在本次作业题目的模考练习记录,如果有则直接更新作答结果
     *
     * @param hrId
     * @param qNum
     * @return
     * @throws Exception
     */
    private void searchExistHomeworkExamRecordAndDelete(Integer hrId, Integer qNum) throws Exception {
        HashMap<String, Object> param = new HashMap<>();
        param.put("homeworkRecordId", hrId);
        param.put("homeworkQuestionNum", qNum);
        TsExamRecord existTer = tsExamRecordsMapper.getByHomeworkInfo(param);
        if (existTer != null) {
            if (!tsExamRecordsMapper.delete(existTer)) {
                throw new Exception("删除作业关联模考联系记录失败,homeworkRecordId:" + hrId + ", homeworkQuestionNum:" + qNum);
            }
        }
    }

    /**
     * 获取作业中模考记录统计信息, 涵盖听说读写四种类型
     *
     * @param homeworkRecordId
     * @param request
     * @param response
     */
    @RequestMapping(value = "/get_homework_answer_result.do", method = RequestMethod.POST)
    public void getHomeworkAnswerResult(@RequestParam(REQUEST_PARAMETER_HOMEWORK_RECORD_ID) Integer homeworkRecordId,
                                        @RequestParam(REQUEST_PARAMETER_HOMEWORK_QUESTION_NUM) Integer homeworkQuestionNum,
                                        HttpServletRequest request,
                                        HttpServletResponse response) {
        HttpResContent<HashMap<String, Object>> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("获取作业所属的模考客观题结果");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_HOMEWORK_RECORD_ID, homeworkRecordId);
            checkParam(REQUEST_PARAMETER_HOMEWORK_QUESTION_NUM, homeworkQuestionNum);
            // do.
            HashMap<String, Object> param = new HashMap<>();
            param.put("homeworkRecordId", homeworkRecordId);
            param.put("homeworkQuestionNum", homeworkQuestionNum);
            TsExamRecord ter = tsExamRecordsMapper.getByHomeworkInfo(param);
            if (ter == null) {
                throw new Exception("获取考试结果记录失败");
            }
            // set.
            HashMap<String, Object> retMap = new HashMap<>();
            ExamSummaryInfo esi = (new Gson()).fromJson(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
            retMap.put("examId", ter.getExamId());
            retMap.put("examRecordId", ter.getId());
            retMap.put("readingAnswerResult", esi.getReadingAnswerResult());
            retMap.put("listeningAnswerResult", esi.getListeningAnswerResult());
            // response.
            saveSuccessMsgAndData(hrc, retMap);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    @RequestMapping(value = "/get_summary_info.do", method = RequestMethod.POST)
    public void getSummaryInfo(@RequestParam(REQUEST_PARAMETER_ID) Integer id,
                               HttpServletRequest request,
                               HttpServletResponse response) {
        HttpResContent<HashMap<String, Object>> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("获取考试结果信息");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_ID, id);
            TsExamRecord ter = tsExamRecordsMapper.getById(id);
            if (ter == null) {
                throw new Exception("获取考试结果记录失败");
            }
            // set.
            HashMap<String, Object> retMap = new HashMap<>();
            retMap.put("examContentType", ter.getExamContentType());
            retMap.put("examType", ter.getExamType());
            ExamSummaryInfo esi = (new Gson()).fromJson(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
            retMap.put("examSummaryInfo", esi);
            // response.
            saveSuccessMsgAndData(hrc, retMap);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

//    /**
//     * 获取模考口语/写作评分记录(全部)
//     * 评分状态根据mark_time判断,空为未评分
//     *
//     * @param markType:speaking,writing
//     * @param request
//     * @param response
//     */
//    @RequestMapping(value = "/get_summary_list.do", method = RequestMethod.POST)
//    public void getSummaryInfoList(@RequestParam(ConstUtil.REQUEST_PARAMETER_MARK_TYPE) String markType,
//                                   HttpServletRequest request, HttpServletResponse response) {
//        HttpResContent<List<MockMarkRecordData>> hrc = new HttpResContent<>(request, response);
//        hrc.setFuncDes("获取模考评分记录");
//        try {
//            // check.
//            checkParam(REQUEST_PARAMETER_MARK_TYPE, markType);
//            List<Map<String, Object>> terList = tsExamRecordsMapper.getListByMarkType(markType);
//            // 根据班级来筛选可查看记录
//            List<String> stdIds = SSysClassesQueueCache.getInstance().getStudentList(hrc.getCurUserId());
//            List<MockMarkRecordData> dataList = new ArrayList<>();
//            for (Map map : terList) {
//                String userId = (String) map.get("user_id");
//                if (stdIds.contains(userId)) {
//                    MockMarkRecordData data = new MockMarkRecordData();
//                    data.setId((Integer) map.get("id"));
//                    data.setExamId((String) map.get("exam_id"));
//                    data.setUserId(userId);
//                    data.setSubjectName((String) map.get("subject_name"));
//                    data.setBeginTime((Date) map.get("begin_time"));
//                    data.setEndTime((Date) map.get("end_time"));
//                    data.setMarkUserId((String) map.get("mark_user_id"));
//                    data.setMarkTime((Date) map.get("mark_time"));
//                    data.setScore((String) map.get("score"));
//                    data.setUserName((String) map.get("user_name"));
//                    data.setMarkUserName((String) map.get("mark_user_name"));
//                    dataList.add(data);
//                }
//            }
//            saveSuccessMsgAndData(hrc, dataList);
//        } catch (Exception e) {
//            saveErrorMsgAndData(hrc, e);
//        } finally {
//            BHttpResUtil.writeResult(hrc);
//        }
//    }

    /**
     * 口语答题列表
     *
     * @param id
     * @param request
     * @param response
     */
    @RequestMapping(value = "/get_speaking_answers.do", method = RequestMethod.POST)
    public void getSpeakingAnswers(@RequestParam(REQUEST_PARAMETER_ID) Integer id,
                                   HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<List<SpeakingAnswerInfo>> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("获取口语考试结果");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_ID, id);
            TsExamRecord ter = tsExamRecordsMapper.getById(id);
            if (ter == null) {
                throw new Exception("获取考试结果记录失败");
            }
            ExamSummaryInfo esi = (new Gson()).fromJson(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
            List<SpeakingAnswerInfo> list = esi.getSpeakingAnswerInfos();
            saveSuccessMsgAndData(hrc, list);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    /**
     * 写作答题列表
     *
     * @param id
     * @param request
     * @param response
     */
    @RequestMapping(value = "/get_writing_answers.do", method = RequestMethod.POST)
    public void getWritingAnswers(@RequestParam(REQUEST_PARAMETER_ID) Integer id,
                                  HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<List<WritingAnswerInfo>> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("获取写作考试结果");
        try {
            checkParam(REQUEST_PARAMETER_ID, id);
            TsExamRecord ter = tsExamRecordsMapper.getById(id);
            if (ter == null) {
                throw new Exception("获取考试结果记录失败");
            }
            ExamSummaryInfo esi = (new Gson()).fromJson(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
            List<WritingAnswerInfo> list = esi.getWritingAnswerInfos();
            saveSuccessMsgAndData(hrc, list);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }


    /**
     * 参数:id,记录id
     * speakingScores: 口语1-6题分数(分数1,2,3,4,5,6)
     */
    @RequestMapping(value = "/save_speaking_score.do", method = RequestMethod.POST)
    public void saveSpeakingScore(@RequestParam(REQUEST_PARAMETER_ID) Integer id,
                                  @RequestParam(ConstUtil.REQUEST_PARAMETER_SPEAKING_SCORE) String speakingScores,
                                  HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<Boolean> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("保存口语评分");
        try {
            String userId = RedisUtils.getInstance().getUserId(request);
            // check.
            checkParam(REQUEST_PARAMETER_ID, id);
            checkParam(REQUEST_PARAMETER_SPEAKING_SCORE, speakingScores);
            TsExamRecord ter = tsExamRecordsMapper.getById(id);
            if (ter == null) {
                throw new Exception("获取考试结果记录失败");
            }
            ExamSummaryInfo esi = (new Gson()).fromJson(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
            List<SpeakingAnswerInfo> list = esi.getSpeakingAnswerInfos();
            speakingScores = speakingScores.trim();
            String[] speakingScoreArr = speakingScores.split(",");
            for (int i = 0; i < speakingScoreArr.length; i++) {
                String speakingScore = speakingScoreArr[i];
                if (!StringUtils.isEmpty(speakingScore)) {
                    for (int j = 0; j < list.size(); j++) {
                        if (list.get(j).getQuestionNum() == (i + 1)) {
                            list.get(j).setScore(Integer.parseInt(speakingScore));
                            break;
                        }
                    }
                }
            }
            String examSummaryInfoStr = (new Gson()).toJson(esi);
            ter.setExamSummaryInfo(examSummaryInfoStr);
            if (!tsExamRecordsMapper.updateExamSummaryInfo(ter)) {
                throw new Exception("保存考试记录中口语评分失败");
            }
            //更新评分记录
            Map<Object, Object> param = new HashMap<>();
            param.put("examId", ter.getExamId());
            param.put("markType", MarkTypeEnum.SPEAKING.getCode());
            TsMockMarkRecord tsMockMarkRecord = tsMockMarkRecordsMapper.getMarkRecord(param);
            if (tsMockMarkRecord == null) {
                throw new Exception("获取口语考试评分记录失败");
            }
            tsMockMarkRecord.setMarkUserId(userId);
            tsMockMarkRecord.setMarkTime(new Date());
            tsMockMarkRecord.setScore(speakingScores);
            if (!tsMockMarkRecordsMapper.updateMarkInfo(tsMockMarkRecord)) {
                throw new Exception("保存口语评分失败");
            }
            if (ExamContentTypeEnum.ALL == ter.getExamContentType()) {
                TsMockReport mr = tsMockReportsMapper.getByExamId(ter.getExamId());
                mr.setSpeakingScore(speakingScores);
                this.updateMockReport(mr);
            }
            //老师批改记录状态修改
            homeworkRecordService.updateTeacherCorrectStatus(ter.getHomeworkRecordId(), MarkTypeEnum.SPEAKING);
            saveSuccessMsgAndData(hrc, true);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }


    /**
     * 参数:id,
     * writingScores:口语1-2题分数(分数1,分数2)
     */
    @RequestMapping(value = "/save_writing_score.do", method = RequestMethod.POST)
    public void saveWritingScore(@RequestParam(REQUEST_PARAMETER_ID) Integer id,
                                 @RequestParam(ConstUtil.REQUEST_PARAMETER_WRITING_SCORE) String writingScores,
                                 HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<Boolean> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("保存写作评分");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_ID, id);
            checkParam(REQUEST_PARAMETER_WRITING_SCORE, writingScores);
            String userId = RedisUtils.getInstance().getUserId(request);
            TsExamRecord ter = tsExamRecordsMapper.getById(id);
            if (ter == null) {
                throw new Exception("获取考试结果记录失败");
            }
            ExamSummaryInfo esi = (new Gson()).fromJson(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
            List<WritingAnswerInfo> list = esi.getWritingAnswerInfos();
            writingScores = writingScores.trim();
            String[] writingScoreArr = writingScores.split(",");
            WritingAnswerInfo writingAnswerInfo;
            for (int i = 0; i < writingScoreArr.length; i++) {
                String writingScore = writingScoreArr[i];
                if (!StringUtils.isEmpty(writingScore)) {
                    for (int j = 0; j < list.size(); j++) {
                        writingAnswerInfo = list.get(j);
                        // 如果單獨只做第二題,進行評分時會出現匹配不到的問題,所以進行單獨處理
                        if (list.size() == 1) {
                            writingAnswerInfo.setScore(Float.parseFloat(writingScore));
                        } else if (writingAnswerInfo.getQuestionNum() == (i + 1)) {
                            writingAnswerInfo.setScore(Float.parseFloat(writingScore));
                            break;
                        }
                    }
                }
            }
            String examSummaryInfoStr = (new Gson()).toJson(esi);
            ter.setExamSummaryInfo(examSummaryInfoStr);
            if (!tsExamRecordsMapper.updateExamSummaryInfo(ter)) {
                throw new Exception("考试记录中写作评分失败");
            }
            //更新评分记录
            Map<Object, Object> param = new HashMap<>();
            param.put("examId", ter.getExamId());
            param.put("markType", MarkTypeEnum.WRITING.getCode());
            TsMockMarkRecord tsMockMarkRecord = tsMockMarkRecordsMapper.getMarkRecord(param);
            if (tsMockMarkRecord == null) {
                throw new Exception("获取写作考试评分记录失败");
            }
            tsMockMarkRecord.setMarkUserId(userId);
            tsMockMarkRecord.setMarkTime(new Date());
            tsMockMarkRecord.setScore(writingScores);
            if (!tsMockMarkRecordsMapper.updateMarkInfo(tsMockMarkRecord)) {
                throw new Exception("保存评分失败");
            }
            if (ExamContentTypeEnum.ALL == ter.getExamContentType()) {
                TsMockReport mr = tsMockReportsMapper.getByExamId(ter.getExamId());
                mr.setWritingScore(writingScores);
                this.updateMockReport(mr);
            }
            //老师批改记录状态修改
            homeworkRecordService.updateTeacherCorrectStatus(ter.getHomeworkRecordId(), MarkTypeEnum.WRITING);
            saveSuccessMsgAndData(hrc, true);
        } catch (Exception e) {
            e.printStackTrace();
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    /**
     * 根据考试ID获取某一条评分记录数据
     *
     * @param examId
     * @param request
     * @param response
     */
    @RequestMapping(value = "/get_mock_mark_record.do", method = RequestMethod.POST)
    public void getMockMarkRecord(@RequestParam(REQUEST_PARAMETER_EXAMINATION_ID) String examId,
                                  HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<TsMockMarkRecord> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("获取一条评分记录");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_EXAMINATION_ID, examId);
            // query.
            TsMockMarkRecord tmmr = tsMockMarkRecordsMapper.getByExamId(examId);
            if (tmmr == null) {
                throw new Exception("获取评分记录失败, examId=" + examId);
            }
            // return.
            saveSuccessMsgAndData(hrc, tmmr);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    /**
     * 通过考试ID获取当前做题进度
     *
     * @param examId
     * @param request
     * @param response
     */
    @RequestMapping(value = "/get_exam_progress_data.do", method = RequestMethod.POST)
    public void getExamProgressData(@RequestParam(REQUEST_PARAMETER_EXAMINATION_ID) String examId,
                                    HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<ExaminationInfo> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("通过考试ID获取当前做题进度");
        try {
            // check.
            checkParam(REQUEST_PARAMETER_EXAMINATION_ID, examId);
            // query.
            // 如果存在过期的考试ID，也可以通过该方式来获取
            ExaminationInfo ei = null;
            if (SExaminationQueueCache.getInstance().containsExamId(examId)) {
                ei = SExaminationQueueCache.getInstance().getExaminationInfo(examId);
            } else if (tsExamRecordsMapper.exist(examId)) {
                // 如果MC中没有记录，则查看expired记录
                TsExamRecord ter = tsExamRecordsMapper.getByExamId(examId);
                if (ter != null) {
                    ei = GJsonUtil.fromJson(ter.getExpiredExamInfo(), ExaminationInfo.class);
                }
            } else {
                throw new Exception("不存在该记录：ExamID=" + examId);
            }
            // return.
            saveSuccessMsgAndData(hrc, ei);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    @RequestMapping(value = "/get_exam_record_info.do", method = RequestMethod.POST)
    public void getExamRecordInfo(@RequestParam(PARAM_EXAM_ID) String examId,
                                  HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<JSONObject> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("获取考试记录信息");
        try {
            // check.
            checkParam(PARAM_EXAM_ID, examId);
            // do.
            TsExamRecord ter = tsExamRecordsMapper.getByExamId(examId);
            if (ter == null) {
                throw new Exception("考试记录不存在或已删除!");
            }
            JSONObject retObj = new JSONObject();
            retObj.put("examContentType", ter.getExamContentType());
            retObj.put("examType", ter.getExamType());
            ExamSummaryInfo esi = JSON.parseObject(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
            retObj.put("examSummaryInfo", esi);
            // return.
            saveSuccessMsgAndData(hrc, retObj);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    /**
     * 获取用户尚未做完的模考记录
     *
     * @param request
     * @param response
     */
    @RequestMapping(value = "/get_exam_cache_data.do", method = RequestMethod.POST)
    public void getCachedExamData(HttpServletRequest request, HttpServletResponse response) {
        HttpResContent<JSONArray> hrc = new HttpResContent<>(request, response);
        hrc.setFuncDes("获取当前用户未做完的模考信息");
        try {
            String userId = RedisUtils.getInstance().getUserId(request);
            // get data and query.
            List<ExaminationInfo> retList = new ArrayList<>();
            String homeworkId = request.getParameter(ConstUtil.REQUEST_PARAMETER_HOMEWORK_ID);
            if (StringUtils.isNotBlank(homeworkId) && StringUtils.isNumeric(homeworkId)) {
                // 如果传递参数含有homework_id，则仅返回作业相关记录列表（多条），否则返回模考相关记录（一条）
                retList = SExaminationQueueCache.getInstance()
                        .getExamCacheDataByUserIdAndHomeworkId(userId, Integer.parseInt(homeworkId));
            } else {
                // query.
                ExaminationInfo ei = SExaminationQueueCache.getInstance().getExamCacheDataByUserId(userId);
                if (ei != null) {
                    retList.add(ei);
                }
            }
            // 有的key是int, 造成前端无法读取json, 用json工具转一下
            JSONArray retArr = JSON.parseArray(JSON.toJSONString(retList));
            // return.
            saveSuccessMsgAndData(hrc, retArr);
        } catch (Exception e) {
            saveErrorMsgAndData(hrc, e);
        } finally {
            BHttpResUtil.writeResult(hrc);
        }
    }

    //更新模考报告中的口语/写作分数
    private void updateMockReport(TsMockReport mr) throws Exception {
        //当口语/写作分数都不为空
        if (!StringUtils.isEmpty(mr.getSpeakingScore()) && !StringUtils.isEmpty(mr.getWritingScore())) {
            if (mr.getStatus() == MockReportStatusEnum.MARKING) {
                mr.setStatus(MockReportStatusEnum.MARKED);
            } else if (mr.getStatus() == MockReportStatusEnum.CREATED) {
                mr.setStatus(MockReportStatusEnum.RECREATE);
            }
            mr.setPdfUrl("");
        }
        if (!tsMockReportsMapper.update(mr)) {
            throw new Exception("更新报告评分记录失败");
        }
    }

    /**
     * 完成考试时,新增口语/写作评分记录
     */
    private boolean saveMockMarkRecord(TsExamRecord ter) {
        ExamContentTypeEnum examContentType = ter.getExamContentType();
        if (ExamContentTypeEnum.ALL == examContentType || ExamContentTypeEnum.SPEAKING == examContentType) {
            TsMockMarkRecord tsMockMarkRecord = new TsMockMarkRecord();
            tsMockMarkRecord.setExamId(ter.getExamId());
            tsMockMarkRecord.setMarkType(MarkTypeEnum.SPEAKING);
            if (!tsMockMarkRecordsMapper.add(tsMockMarkRecord)) {
                BLogUtil.info("新增口语评分记录失败,考试记录id:" + ter.getId());
                return false;
            }
        }
        if (ExamContentTypeEnum.ALL == examContentType || ExamContentTypeEnum.WRITING == examContentType) {
            TsMockMarkRecord tsMockMarkRecord = new TsMockMarkRecord();
            tsMockMarkRecord.setExamId(ter.getExamId());
            tsMockMarkRecord.setMarkType(MarkTypeEnum.WRITING);
            if (!tsMockMarkRecordsMapper.add(tsMockMarkRecord)) {
                BLogUtil.info("新增写作评分记录失败,考试记录id:" + ter.getId());
                return false;
            }
        }
        return true;
    }

    /**
     * 获取考试统计信息
     *
     * @param examinationInfo
     * @return
     */
    private ExamSummaryInfo getExamSummaryInfo(ExaminationInfo examinationInfo) throws Exception {
        ExamSummaryInfo examSummaryInfo = new ExamSummaryInfo();
        try {
            // reading.
            examSummaryInfo.setReadingSummaryInfos(
                    getReadingSummaryInfoList(examinationInfo.getExamReadingInfo())
            );
            // listening.
            examSummaryInfo.setListeningSummaryInfos(
                    getListeningSummaryInfoList(examinationInfo.getExamListeningInfo())
            );
            // speaking.
            examSummaryInfo.setSpeakingAnswerInfos(
                    getSpeakingAnswerInfoList(examinationInfo.getExamSpeakingInfo())
            );
            // writing.
            examSummaryInfo.setWritingAnswerInfos(
                    getWritingAnswerInfoList(examinationInfo.getExamWritingInfo())
            );
            // calculate reading and listening result info.
            examSummaryInfo.calAnswerResultInfo();
            return examSummaryInfo;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 获取写作部分作答统计信息
     *
     * @param ewi
     * @return
     */
    private List<WritingAnswerInfo> getWritingAnswerInfoList(ExamWritingInfo ewi) {
        List<WritingAnswerInfo> writingAnswerInfos = new ArrayList<>();
        if (ewi != null) {
            for (Map.Entry<Integer, String> entry : ewi.getAnswerMap().entrySet()) {
                WritingAnswerInfo wai = new WritingAnswerInfo();
                wai.setQuestionNum(entry.getKey());
                wai.setStudentAnswer(entry.getValue());
                wai.setQuestionInfo(ewi.getQuestionMap().get(entry.getKey()));
                writingAnswerInfos.add(wai);
            }
        }
        return writingAnswerInfos;
    }

    /**
     * 获取口语部分作答统计信息
     *
     * @param esi
     * @return
     */
    private List<SpeakingAnswerInfo> getSpeakingAnswerInfoList(ExamSpeakingInfo esi) {
        List<SpeakingAnswerInfo> speakingAnswerInfos = new ArrayList<>();
        if (esi != null) {
            for (Map.Entry<Integer, String> entry : esi.getAnswerMap().entrySet()) {
                SpeakingAnswerInfo sai = new SpeakingAnswerInfo();
                sai.setQuestionNum(entry.getKey());
                sai.setStudentAnswer(entry.getValue());
                speakingAnswerInfos.add(sai);
            }
            for (SpeakingAnswerInfo info : speakingAnswerInfos) {
                String questionTitle = esi.getQuestionTitleMap().get(info.getQuestionNum());
                info.setQuestionTitle(questionTitle);
            }
        }
        return speakingAnswerInfos;
    }

    /**
     * 获取听力部分作答统计信息
     *
     * @param eli
     * @return
     */
    private List<ListeningSummaryInfo> getListeningSummaryInfoList(ExamListeningInfo eli) {
        List<ListeningSummaryInfo> listeningSummaryInfoList = new ArrayList<>();
        if (eli != null) {
            for (Map.Entry<Integer, Integer> entry : eli.getArticleMap().entrySet()) {
                ListeningSummaryInfo lsi = new ListeningSummaryInfo();
                lsi.setArticleNum(entry.getKey());
                TsListeningArticle tla = tsListeningArticlesMapper.getById(entry.getValue());
                lsi.setSectionNum(tla.getSectionNum());
                List<ListeningAnswerInfo> answerInfoList = new ArrayList<>();
                if (tla != null) {
                    HashMap<String, Object> param = new HashMap<>();
                    param.put("subjectName", tla.getSubjectName());
                    param.put("tsListeningArticleId", tla.getId());
                    List<TsListeningQuestion> questionList = tsListeningQuestionsMapper.getQuestions(param);
                    for (Map.Entry<Integer, String> answer : eli.getAnswerMap().get(entry.getKey()).entrySet()) {
                        ListeningAnswerInfo lai = new ListeningAnswerInfo();
                        lai.setQuestionNum(answer.getKey());
                        lai.setStudentAnswer(answer.getValue());
                        for (TsListeningQuestion tlq : questionList) {
                            if (tlq.getQuestionNum().equals(answer.getKey())) {
                                lai.setQuestionTitle(tlq.getQuestionXml().getTitle());
                                lai.setArticleId(tla.getId());
                                if (tlq.getQuestionXml() != null) {
                                    lai.setCorrectAnswer(StringUtils.join(tlq.getQuestionXml().getAnswer(), ","));
                                } else {
                                    lai.setCorrectAnswer("");
                                }
                                break;
                            }
                        }
                        answerInfoList.add(lai);
                    }
                }
                lsi.setAnswerInfoList(answerInfoList);
                listeningSummaryInfoList.add(lsi);
            }
        }
        return listeningSummaryInfoList;
    }

    /**
     * 获取阅读部分作答统计信息
     *
     * @param eri
     * @return
     */
    private List<ReadingSummaryInfo> getReadingSummaryInfoList(ExamReadingInfo eri) {
        List<ReadingSummaryInfo> readingSummaryInfoList = new ArrayList<>();
        if (eri != null) {
            for (Map.Entry<Integer, Integer> entry : eri.getArticleMap().entrySet()) {
                ReadingSummaryInfo rsi = new ReadingSummaryInfo();
                rsi.setArticleNum(entry.getKey());
                TsReadingArticle tra = tsReadingArticleDAO.getById(entry.getValue());
                rsi.setArticleTitle(tra.getArticleTitle());
                List<ReadingAnswerInfo> answerInfoList = new ArrayList<>();
                if (tra != null) {
                    List<TsReadingQuestion> questionList = tsReadingQuestionDAO.getQuestions(tra.getSubjectName(), entry.getKey());
                    for (Map.Entry<Integer, String> answer : eri.getAnswerMap().get(entry.getKey()).entrySet()) {
                        ReadingAnswerInfo rai = new ReadingAnswerInfo();
                        rai.setQuestionNum(answer.getKey());
                        rai.setStudentAnswer(answer.getValue());
                        for (TsReadingQuestion trq : questionList) {
                            if (trq.getQuestionNum().equals(answer.getKey())) {
                                if (trq.getQuestionXml() != null) {
                                    rai.setQuestionTitle(trq.getQuestionXml().getTitle());
                                    rai.setCorrectAnswer(StringUtils.join(trq.getQuestionXml().getAnswer(), ","));
                                } else {
                                    rai.setQuestionTitle("");
                                    rai.setCorrectAnswer("");
                                }
                                break;
                            }
                        }
                        answerInfoList.add(rai);
                    }
                }
                rsi.setAnswerInfoList(answerInfoList);
                readingSummaryInfoList.add(rsi);
            }
        }
        return readingSummaryInfoList;
    }

    //生成模考报告记录
    public boolean createMockReport(TsExamRecord ter, String userName) throws Exception {
        ExamSummaryInfo esi = (new Gson()).fromJson(ter.getExamSummaryInfo(), ExamSummaryInfo.class);
        List<ReadingSummaryInfo> readingList = esi.getReadingSummaryInfos();
        int readingScore = 0;
        TsMockReport tsMockReport = new TsMockReport();
        int readingCorrectNum = 0, readingWrongNum = 0, readingUndoNum = 0, readingScoreIndex = 0;//正确个数,错误个数,未答个数,得分
        if (readingList != null && readingList.size() > 0) {
            String questionTitle, correctAnswer, studentAnswer;
            for (ReadingSummaryInfo rsi : readingList) {
                List<ReadingAnswerInfo> infoList = rsi.getAnswerInfoList();
                for (ReadingAnswerInfo info : infoList) {
                    questionTitle = info.getQuestionTitle();
                    correctAnswer = info.getCorrectAnswer();
                    studentAnswer = info.getStudentAnswer();
                    if (!StringUtils.isEmpty(studentAnswer)) {
                        // 判分 summary类型的题
                        if (correctAnswer.length() == 5) {
                            // 分值转换
                            int[] scoreArr = {0, 0, 1, 2};
                            List<String> stuList = new ArrayList<>(Arrays.asList(studentAnswer.toLowerCase().split(",")));
                            List<String> corList = new ArrayList<>(Arrays.asList(correctAnswer.toLowerCase().split(",")));
                            corList.retainAll(stuList);
                            readingCorrectNum += corList.size();
                            readingScoreIndex += scoreArr[corList.size()];
                            readingWrongNum += (3 - corList.size());
                        } else {
                            if (studentAnswer.equalsIgnoreCase(correctAnswer)) {
                                readingCorrectNum++;
                                readingScoreIndex = readingScoreIndex + MockUtil.matchesScore(questionTitle);//答对
                            } else {
                                readingWrongNum++;//答错
                            }
                        }
                    } else {//未答题
                        readingUndoNum++;
                    }
                }
            }
            if (readingScoreIndex > readingGrad.length) {
                readingScore = fullScore;
            } else {
                //阅读有几套总分不满45分,需要换算一下
                readingScore = readingGrad[MockUtil.getReadingScore(ter.getSubjectName(), readingScoreIndex)];
            }
        }
        BLogUtil.info("计算整套模考报告:阅读部分完毕.");
        List<ListeningSummaryInfo> listeningList = esi.getListeningSummaryInfos();
        int listeningScore = 0;
        int listeningCorrectNum = 0, listeningWrongNum = 0, listeningUndoNum = 0;//未答题
        if (listeningList != null && listeningList.size() > 0) {
            String correctAnswer, studentAnswer;
            for (ListeningSummaryInfo rsi : listeningList) {
                List<ListeningAnswerInfo> infoList = rsi.getAnswerInfoList();
                for (ListeningAnswerInfo info : infoList) {
                    correctAnswer = info.getCorrectAnswer();
                    studentAnswer = info.getStudentAnswer();
                    if (!StringUtils.isEmpty(studentAnswer)) {
                        if (studentAnswer.equalsIgnoreCase(correctAnswer)) {
                            listeningCorrectNum++;
                        } else {
                            listeningWrongNum++;
                        }
                    } else {
                        listeningUndoNum++;
                    }
                }
            }
            //如果有缺题,正确个数不变,换算30分时,个数加一
            int scoreIndex = listeningCorrectNum;
            for (String subjectName : listeningLacks) {
                if (subjectName.equalsIgnoreCase(ter.getSubjectName())) {
                    scoreIndex++;
                    break;
                }
            }
            if (scoreIndex > listenGrad.length) {
                listeningScore = fullScore;
            } else {
                listeningScore = listenGrad[scoreIndex];
            }
        }
        BLogUtil.info("计算整套模考报告:听力部分完毕.");
        tsMockReport.setExamId(ter.getExamId());
        tsMockReport.setUserId(ter.getUserId());
        tsMockReport.setUserName(userName);
        tsMockReport.setReadingScore(readingCorrectNum + "," + readingWrongNum + "," + readingUndoNum + "," + readingScore);
        tsMockReport.setListeningScore(listeningCorrectNum + "," + listeningWrongNum + "," + listeningUndoNum + "," + listeningScore);
        tsMockReport.setStatus(MockReportStatusEnum.MARKING);
        BLogUtil.info("整套模考报告阅读和听力分数计算完毕.");
        // 如果同一考试id已经存在记录, 则先删除该条记录,然后再同一进行添加
        TsMockReport tmr = tsMockReportsMapper.getByExamId(tsMockReport.getExamId());
        if (tmr != null) {
            BLogUtil.info("整套模考报告存在相同记录,准备删除ing.");
            if (!tsMockReportsMapper.delete(tmr.getId())) {
                throw new Exception("删除模考报告记录失败,examId:" + tsMockReport.getExamId());
            }
        }
        return tsMockReportsMapper.add(tsMockReport);
    }

    /**
     * 通过套题名称获取考试阅读部分空白作答模板
     *
     * @param subjectName
     * @return
     */
    private ExamReadingInfo getBlankExamReadingInfo(String subjectName, String numVal) throws Exception {
        Map<Integer, Integer> readingArticleMap = new HashMap<>();
        Map<Integer, Map<Integer, String>> readingAnswerMap = new HashMap<>();
        List<Integer> articleNumList = getNumListFromVal(numVal);
        List<TsReadingArticle> readingArticles = tsReadingArticleDAO.getList(subjectName);
        if (readingArticles != null && readingArticles.size() > 0) {
            for (TsReadingArticle article : readingArticles) {
                // 判断单篇文章练习的情况,并进行模板过滤;如果没有传递该参数,则默认为全部创建
                if (articleNumList.size() == 0 || articleNumList.contains(article.getArticleNum())) {
                    readingArticleMap.put(article.getArticleNum(), article.getId());
                    List<TsReadingQuestion> rQuestions = tsReadingQuestionDAO.getQuestions(subjectName, article.getArticleNum());
                    Map<Integer, String> map = new HashMap<>();
                    if (rQuestions != null && rQuestions.size() > 0) {
                        for (TsReadingQuestion question : rQuestions) {
                            map.put(question.getQuestionNum(), "");
                        }
                    }
                    readingAnswerMap.put(article.getArticleNum(), map);
                }
            }
        }
        ExamReadingInfo eri = new ExamReadingInfo();
        eri.setCurProgress("1-1");
        eri.setAnswerTime(0);
        eri.setArticleMap(readingArticleMap);
        eri.setAnswerMap(readingAnswerMap);
        return eri;
    }

    /**
     * 通过套题名称获取考试听力部分空白作答模板
     *
     * @param subjectName
     * @return
     */
    private ExamListeningInfo getBlankExamListeningInfo(String subjectName, String numVal) throws Exception {
        Map<Integer, Integer> articleMap = new HashMap<>();
        Map<Integer, Map<Integer, String>> answerMap = new HashMap<>();
        List<Integer> articleNumList = getNumListFromVal(numVal);
        List<TsListeningArticle> listeningArticles = tsListeningArticlesMapper.getListBySubjectName(subjectName);
        if (listeningArticles != null && listeningArticles.size() > 0) {
            for (TsListeningArticle article : listeningArticles) {
                // 判断单篇文章练习的情况,并进行模板过滤;如果没有传递该参数,则默认为全部创建
                if (articleNumList.size() == 0 || articleNumList.contains(article.getArticleNum())) {
                    articleMap.put(article.getArticleNum(), article.getId());
                    HashMap<String, Object> param = new HashMap<>();
                    param.put(MAPPER_PARAM_SUBJECT_NAME, subjectName);
                    param.put(MAPPER_PARAM_LISTENING_ARTICLE_ID, article.getId());
                    List<TsListeningQuestion> lQuestions = tsListeningQuestionsMapper.getQuestions(param);
                    Map<Integer, String> map = new HashMap<>();
                    if (lQuestions != null && lQuestions.size() > 0) {
                        for (TsListeningQuestion question : lQuestions) {
                            map.put(question.getQuestionNum(), "");
                        }
                    }
                    answerMap.put(article.getArticleNum(), map);
                }
            }
        }
        ExamListeningInfo eli = new ExamListeningInfo();
        eli.setCurProgress("1-1");
        eli.setAnswerTime(0);
        eli.setArticleMap(articleMap);
        eli.setAnswerMap(answerMap);
        return eli;
    }

    /**
     * 通过套题名称获取考试口语部分空白作答模板
     *
     * @param subjectName
     * @return
     */
    private ExamSpeakingInfo getBlankExamSpeakingInfo(String subjectName, String numVal) throws Exception {
        Map<Integer, String> speakingQuestionTitleMap = new HashMap<>();
        Map<Integer, String> speakingAnswerMap = new HashMap<>();
        HashMap<String, Object> param = new HashMap<>();
        param.put(MAPPER_PARAM_SUBJECT_NAME, subjectName);
        List<Integer> qNumList = getNumListFromVal(numVal);
        List<TsSpeakingQuestion> sQuestions = tsSpeakingQuestionsMapper.getQuestions(param);
        if (sQuestions != null && sQuestions.size() > 0) {
            for (TsSpeakingQuestion question : sQuestions) {
                // 判断单篇文章练习的情况,并进行模板过滤;如果没有传递该参数,则默认为全部创建
                if (qNumList.size() == 0 || qNumList.contains(question.getQuestionNum())) {
                    speakingQuestionTitleMap.put(question.getQuestionNum(),
                            question.getQuestionXml().getTitle().get(XML_NODE_NAME_SCRIPT));
                    speakingAnswerMap.put(question.getQuestionNum(), "");
                }
            }
        }
        ExamSpeakingInfo esi = new ExamSpeakingInfo();
        esi.setCurProgress("1");
        esi.setAnswerTime(0);
        esi.setQuestionTitleMap(speakingQuestionTitleMap);
        esi.setAnswerMap(speakingAnswerMap);
        return esi;
    }

    /**
     * 通过套题名称获取考试写作部分空白作答模板
     *
     * @param subjectName
     * @return
     */
    private ExamWritingInfo getBlankExamWritingInfo(String subjectName, String numVal) throws Exception {
        Map<Integer, String> writingAnswerMap = new HashMap<>();
        Map<Integer, String> writingQuestionMap = new HashMap<>();
        HashMap<String, Object> param = new HashMap<>();
        param.put(MAPPER_PARAM_SUBJECT_NAME, subjectName);
        List<Integer> qNumList = getNumListFromVal(numVal);
        List<TsWritingQuestion> wQuestions = tsWritingQuestionsMapper.getQuestions(param);
        if (wQuestions != null && wQuestions.size() > 0) {
            for (TsWritingQuestion question : wQuestions) {
                // 判断单篇文章练习的情况,并进行模板过滤;如果没有传递该参数,则默认为全部创建
                if (qNumList.size() == 0 || qNumList.contains(question.getQuestionNum())) {
                    writingAnswerMap.put(question.getQuestionNum(), "");
                    writingQuestionMap.put(question.getQuestionNum(), question.getQuestionXml().getQuestion());
                }
            }
        }
        ExamWritingInfo ewi = new ExamWritingInfo();
        ewi.setCurProgress("1");
        ewi.setAnswerTime(0);
        ewi.setAnswerMap(writingAnswerMap);
        ewi.setQuestionMap(writingQuestionMap);
        return ewi;
    }

    /**
     * 从序号字符串中获取序号数组
     *
     * @param numVal
     * @return
     */
    private List<Integer> getNumListFromVal(String numVal) {
        List<Integer> articleNumList = new ArrayList<>();
        if (StringUtils.isNotBlank(numVal)) {
            String[] arr = numVal.split(",");
            for (String s : arr) {
                articleNumList.add(Integer.parseInt(s));
            }
        }
        return articleNumList;
    }

}
